#include "simuhost.h"
#include "math.h"


SimuHost::SimuHost(unsigned int st, unsigned int ct, double td, double hs, double ic, unsigned int timeToFailure, unsigned int timeToRepair)
{
    ipc = ic;
    startTime = st;
    currentTime = ct;
    timeDenom = td;
    clockSpeed = hs;
    isOn = false;
    isSleeping = false;
    hasFailed = false;
    MTTF = timeToFailure; // needs to be calculated in number of time denominations
    MTTR = timeToRepair;
    ins = (unsigned long long) (ipc*clockSpeed*1000000000);
    failTime = 0;
    load = 0;
    processedLoad = 0;
}

SimuHost::SimuHost()
{
    ipc = 1;
    startTime = 0;
    currentTime = 0;
    timeDenom = .001;	// default 1 millisecond time denomination
    clockSpeed = 1.0;	// default 1 GHz clock speed
    isOn = false;
    isSleeping = false;
    hasFailed = false;
    MTTF = 31556926; // default 1 year MTTF
    MTTR = 43200; // default 12 hour MTTR
    ins = (unsigned long long) (ipc*clockSpeed*1000000000);
    failTime = 0;
    load = 0;
    processedLoad = 0;
}

bool SimuHost::hardwareFailed()
{
    return hasFailed;
}

bool SimuHost::turnOn(bool on)
{
    if (on == true)
    {
        isOn = true;
        return true;
    }
    else
    {
        isOn = false;
        return true;
    }
    return false;

}

bool SimuHost::sleep(bool on)
{
    if (on == true)
    {
        isSleeping = true;
        return true;
    }
    else
    {
        isSleeping = false;
        return true;
    }
    return false;

}

bool SimuHost::allocateLoad(unsigned long long instructions)
{
    load += instructions;
    return true;
}

unsigned long long SimuHost::currentLoad()
{
    return load;
}

unsigned long long SimuHost::generateLoad(unsigned long long min, unsigned long long max)
{
    if (max < min) {
	return min;
    }

    unsigned long long load = (((unsigned long long) rand()) << 32) | rand();
    
    load -= min;
    load %= max;
    load += min;

    return load;
}

void SimuHost::process()
{
    if (!hasFailed) {
        processedLoad = load;
        if (ins >= load) {
            load = 0;
        }
        else {
            load = load - ins;
        }

        processedLoad -= load;
        currentTime += timeDenom;

        double failurePercentage = 0;
        if (currentTime >= (unsigned int) (101.152003093 * (double)MTTF)) {
           failurePercentage = 0.9;
        }
        else {
           failurePercentage = pow(2, (currentTime * 100 / MTTF) - 101);
           if (failurePercentage < 0.0001) {
               failurePercentage = 0.0001;
           }
        }
        int failRoll = rand() % 10000;

        if (failRoll < (int) (failurePercentage * 10000)) {
            hasFailed = true;
            failTime = currentTime;
            load = 0;
        }
    }
}

bool SimuHost::fix()
{
    if (hasFailed) {
        if (currentTime >= failTime + MTTR) {
            hasFailed = false;
            return true;
        }
    }
    return false;
}

bool SimuHost::sync(unsigned int syncTime)
{
    if (!hasFailed) {
        currentTime = syncTime;
        process();
        return true;
    }
    else {
        fix();
        return false;
    }
}

unsigned short SimuHost::loadPercentage()
{
    return (unsigned short) (processedLoad * 100 / ins);
}
